#ifndef AABBOX
#define AABBOX

#include "vector2d.h"
#include "vector3d.h"

namespace sleek
{
    namespace core
    {
        namespace math
        {
            template <typename T>
            class aabbox2d
            {
                public:
                    aabbox2d(T x0, T y0, T x1, T y1){ upperleft = vector2d<T>(x0,y0); lowerright = vector2d<T>(x1,y1); }
                    aabbox2d(vector2d<T> min = vector2d<T>(0,0), vector2d<T> max = vector2d<T>(0,0)){ upperleft = min; lowerright = max; }
                    virtual ~aabbox2d(){}

                    inline void clear() { upperleft = lowerright = vector2d<T>((T)0, (T)0); }
                    inline void setUpperLeft(vector2d<T> a){ upperleft = a; }
                    inline void setLowerRight(vector2d<T> a){ lowerright = a; }
                    inline void setCenterBox(vector2d<T> a){ upperleft = a-(getSize()/2); lowerright = a+(getSize()/2); }

                    inline aabbox2d<T> operator + (vector2d<T> i) { return aabbox2d<T>(upperleft+i, lowerright+i); }
                    inline void operator = (aabbox2d<T> i) { upperleft = i.upperleft; lowerright = i.lowerright; }

                    inline void setSizeFromUpperLeft(vector2d<T> a){ lowerright = upperleft+a; }
                    inline void setSizeFromLowerRight(vector2d<T> a){ upperleft = lowerright-a; }
                    inline void setSizeFromCenter(vector2d<T> a) { vector2d<T> center = getCenter(); upperleft = center-(a/2); lowerright = center+(a/2); }

                    inline vector2d<T> getUpperLeft() { return upperleft; }
                    inline vector2d<T> getLowerRight() { return lowerright; }
                    inline vector2d<T> getCenter() { return upperleft+getSize()/2; }
                    inline vector2d<T> getSize() { return lowerright-upperleft; }

                    inline bool intersect(vector2d<T> a){ if(upperleft < a && lowerright > a) return true; return false; }
                    inline vector2d<T> minimise()
                    {
                        vector2d<T> pos = getUpperLeft(), size = getSize();
                        upperleft = vector2d<T>();
                        setSizeFromCenter(size);
                        return pos;
                    }
                    inline vector2d<T> center()
                    {
                        vector2d<T> pos = getCenter(), size = getSize();
                            upperleft = pos-(size/2);
                            lowerright = pos+(size/2);
                        return pos;
                    }
                    inline void addInternalPoint(core::math::vector2d<T> a)
                    {
                        if(a.width > lowerright.width) lowerright.width = a.width;
                        if(a.height > lowerright.height) lowerright.width = a.height;

                        if(a.width < upperleft.width) upperleft.width = a.width;
                        if(a.height < upperleft.height) upperleft.width = a.height;
                    }
                    inline void merge(aabbox2d<T> a)
                    {
                        addInternalPoint(a.upperleft);
                        addInternalPoint(a.lowerright);
                    }
                protected:
                    vector2d<T> upperleft, lowerright;
            };
            template <typename T>
            class aabbox3d
            {
                public:
                    aabbox3d(T x0, T y0, T z0, T x1, T y1, T z1){ upperleft = vector3d<T>(x0,y0,z0); lowerright = vector3d<T>(x1,y1,z1); }
                    aabbox3d(vector3d<T> min = vector3d<T>(0,0,0), vector3d<T> max = vector3d<T>(0,0,0)){ upperleft = min; lowerright = max; }
                    virtual ~aabbox3d(){}

                    inline void clear() { upperleft = lowerright = vector3d<T>((T)0, (T)0, T(0)); }
                    inline void setUpperLeft(vector3d<T> a){ upperleft = a; }
                    inline void setLowerRight(vector3d<T> a){ lowerright = a; }
                    inline void setCenterBox(vector3d<T> a){ upperleft = a-(getSize()/2); lowerright = a+(getSize()/2); }

                    inline aabbox3d<T> operator + (vector3d<T> i) { return aabbox3d<T>(upperleft+i, lowerright+i); }
                    inline void operator = (aabbox3d<T> i) { upperleft = i.upperleft; lowerright = i.lowerright; }

                    inline void setSizeFromUpperLeft(vector3d<T> a){ lowerright = upperleft+a; }
                    inline void setSizeFromLowerRight(vector3d<T> a){ upperleft = lowerright-a; }
                    inline void setSizeFromCenter(vector3d<T> a) { vector3d<T> center = getCenter(); upperleft = center-(a/2); lowerright = center+(a/2); }

                    inline vector3d<T> getUpperLeft() { return upperleft; }
                    inline vector3d<T> getLowerRight() { return lowerright; }
                    inline vector3d<T> getCenter() { return upperleft+(getSize()/2); }
                    inline vector3d<T> getSize() { return lowerright-upperleft; }

                    inline bool intersect(vector3d<T> a){ if(upperleft < a && lowerright > a) return true; return false; }
                    inline vector3d<T> minimise()
                    {
                        vector3d<T> pos = getUpperLeft(), size = getSize();
                        upperleft = vector3d<T>();
                        setSizeFromCenter(size);
                        return pos;
                    }
                    inline vector3d<T> center()
                    {
                        vector3d<T> pos = getCenter(), size = getSize();
                            upperleft = pos-(size/2);
                            lowerright = pos+(size/2);
                        return pos;
                    }
                    inline void addInternalPoint(core::math::vector3d<T> a)
                    {
                        if(a.x > lowerright.x) lowerright.x = a.x;
                        if(a.y > lowerright.y) lowerright.x = a.y;
                        if(a.z > lowerright.z) lowerright.x = a.z;

                        if(a.x < upperleft.x) upperleft.x = a.x;
                        if(a.y < upperleft.y) upperleft.x = a.y;
                        if(a.z < upperleft.z) upperleft.x = a.z;
                    }
                    inline void merge(aabbox3d<T> a)
                    {
                        addInternalPoint(a.upperleft);
                        addInternalPoint(a.lowerright);
                    }
                protected:
                    vector3d<T> upperleft, lowerright;
            };


            typedef aabbox2d<u8>  aabbox2dc;
            typedef aabbox2d<f32> aabbox2df;
            typedef aabbox2d<int> aabbox2di;
            typedef aabbox2d<u32> aabbox2du;
            typedef aabbox2d<s32> aabbox2ds;

            typedef aabbox3d<u8>  aabbox3dc;
            typedef aabbox3d<f32> aabbox3df;
            typedef aabbox3d<int> aabbox3di;
            typedef aabbox3d<u32> aabbox3du;
            typedef aabbox3d<s32> aabbox3ds;
        }
    }
}

#endif
